import json
import datetime
import uuid
import os
import re
import math 
import binascii
from flask import Flask, request, jsonify, render_template, abort, url_for
from urllib.parse import quote_plus 
from collections import defaultdict

app = Flask(__name__)

# --- 配置 ---
DATA_FILE = 'data_store.json'
DATA_STORE = {} # 存储原始的 message_entry: {raw_post_data, parsed_content, receive_time}

# 高德地图JS API Key
AMAP_JSAPI_KEY = '9374c8276711715a3e4a6b5180e8ca63'


# --- 数据持久化辅助函数 ---
def load_data():
    """从文件中加载数据到 DATA_STORE"""
    global DATA_STORE
    print(f"[{datetime.datetime.now()}] [INFO] 尝试从 {DATA_FILE} 加载数据...")
    if os.path.exists(DATA_FILE):
        try:
            with open(DATA_FILE, 'r', encoding='utf-8') as f:
                loaded_data = json.load(f)
                if not isinstance(loaded_data, dict):
                    raise ValueError("加载的数据不是字典格式。")
                DATA_STORE = loaded_data
            
            # 在加载数据后，对每个ID的消息列表进行排序，确保最新消息在最前面
            for id_num, messages in DATA_STORE.items():
                if not isinstance(messages, list):
                    print(f"[{datetime.datetime.now()}] [WARN] ID '{id_num}' 下的数据不是列表，将跳过或重置。")
                    DATA_STORE[id_num] = []
                    continue
                DATA_STORE[id_num] = sorted(
                    messages, 
                    key=lambda x: datetime.datetime.fromisoformat(x.get('receive_time', '1970-01-01T00:00:00')), 
                    reverse=True
                )
            print(f"[{datetime.datetime.now()}] [INFO] 数据从 {DATA_FILE} 加载成功，包含 {len(DATA_STORE)} 个ID。")
        except json.JSONDecodeError:
            print(f"[{datetime.datetime.now()}] [ERROR] {DATA_FILE} 不是有效的 JSON 文件，将初始化为空数据存储。")
            DATA_STORE = {}
        except ValueError as ve:
            print(f"[{datetime.datetime.now()}] [ERROR] 加载数据时发生值错误: {ve}，将初始化为空数据存储。")
            DATA_STORE = {}
        except Exception as e:
            print(f"[{datetime.datetime.now()}] [ERROR] 加载数据时发生未知错误: {e}，将初始化为空数据存储。")
            DATA_STORE = {}
    else:
        print(f"[{datetime.datetime.now()}] [INFO] 数据文件 {DATA_FILE} 不存在，将初始化为空数据存储。")
        DATA_STORE = {}

def save_data():
    """将 DATA_STORE 中的数据保存到文件"""
    try:
        with open(DATA_FILE, 'w', encoding='utf-8') as f:
            json.dump(DATA_STORE, f, indent=2, ensure_ascii=False)
    except Exception as e:
        print(f"[{datetime.datetime.now()}] [ERROR] 保存数据到 {DATA_FILE} 时发生错误: {e}")

# --- 电文解析辅助函数 ---

def _parse_old_protocol(byte_data, hex_str):
    """
    解析旧协议（0xA4开头）的电文内容。
    """
    parsed_data = {"raw_hex_content": hex_str, "protocol_type": "旧协议 (0xA4)"}
    offset = 0
    total_len = len(byte_data)

    # 1. 数据标识 (1 byte): A4
    if total_len < offset + 1:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析数据标识。"
        return parsed_data
    data_id = byte_data[offset]
    parsed_data['数据标识'] = f"0x{data_id:02X}"
    if data_id != 0xA4:
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 数据标识不是 0xA4。"
    offset += 1

    # 2. 定位时间 (8 bytes): hh:mm:ss
    if total_len < offset + 8:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析定位时间。"
        return parsed_data
    try:
        parsed_data['定位时间'] = byte_data[offset : offset + 8].decode('ascii')
    except UnicodeDecodeError:
        parsed_data['定位时间'] = f"<{binascii.hexlify(byte_data[offset : offset + 8]).decode()}> (解码失败)"
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 定位时间解码为 ASCII 失败。"
    offset += 8

    # 3. 纬度半球 (1 byte): N/S
    if total_len < offset + 1:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析纬度半球。"
        return parsed_data
    try:
        parsed_data['纬度半球'] = byte_data[offset : offset + 1].decode('ascii')
    except UnicodeDecodeError:
        parsed_data['纬度半球'] = f"<{binascii.hexlify(byte_data[offset : offset + 1]).decode()}> (解码失败)"
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 纬度半球解码为 ASCII 失败。"
    offset += 1

    # 4. 纬度 (10 bytes): ddmm.mmmmm
    if total_len < offset + 10:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析纬度。"
        return parsed_data
    try:
        parsed_data['原始纬度值'] = byte_data[offset : offset + 10].decode('ascii')
    except UnicodeDecodeError:
        parsed_data['原始纬度值'] = f"<{binascii.hexlify(byte_data[offset : offset + 10]).decode()}> (解码失败)"
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 原始纬度值解码为 ASCII 失败。"
    offset += 10

    # 5. 经度半球 (1 byte): E/W
    if total_len < offset + 1:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析经度半球。"
        return parsed_data
    try:
        parsed_data['经度半球'] = byte_data[offset : offset + 1].decode('ascii')
    except UnicodeDecodeError:
        parsed_data['经度半球'] = f"<{binascii.hexlify(byte_data[offset : offset + 1]).decode()}> (解码失败)"
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 经度半球解码为 ASCII 失败。"
    offset += 1

    # 6. 经度 (11 bytes): dddmm.mmmmm
    if total_len < offset + 11:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析经度。"
        return parsed_data
    try:
        parsed_data['原始经度值'] = byte_data[offset : offset + 11].decode('ascii')
    except UnicodeDecodeError:
        parsed_data['原始经度值'] = f"<{binascii.hexlify(byte_data[offset : offset + 11]).decode()}> (解码失败)"
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 原始经度值解码为 ASCII 失败。"
    offset += 11

    # 7. 高程 (8 bytes): ±xxxxx.x
    if total_len < offset + 8:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析高程。"
        return parsed_data
    try:
        parsed_data['高程'] = byte_data[offset : offset + 8].decode('ascii')
    except UnicodeDecodeError:
        parsed_data['高程'] = f"<{binascii.hexlify(byte_data[offset : offset + 8]).decode()}> (解码失败)"
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 高程解码为 ASCII 失败。"
    offset += 8

    # 8. 隔离符 (1 byte): '-' (0x2D)
    if total_len < offset + 1:
        parsed_data['parse_status_text'] = "解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "数据长度不足，无法解析隔离符。"
        return parsed_data
    separator = byte_data[offset]
    parsed_data['隔离符'] = f"0x{separator:02X}"
    if separator != 0x2D:
        parsed_data['parse_warning_detail'] = parsed_data.get('parse_warning_detail', '') + " 隔离符不是 '-' (0x2D)。"
    offset += 1

    # 9. 自定义数据 (剩余字节) - 混合 GBK / ASCII 解析
    remaining_bytes = byte_data[offset:]
    custom_data_decoded_parts = []
    i = 0
    
    while i < len(remaining_bytes):
        # 尝试解析 GBK (2字节)
        if i + 1 < len(remaining_bytes):
            try:
                char_gbk = remaining_bytes[i : i + 2].decode('gbk')
                custom_data_decoded_parts.append(char_gbk)
                i += 2
                continue
            except UnicodeDecodeError:
                pass # 不是有效的 GBK 字符对，尝试作为 ASCII
        
        # 尝试解析 ASCII (1字节)
        try:
            char_ascii = remaining_bytes[i : i + 1].decode('ascii')
            custom_data_decoded_parts.append(char_ascii)
            i += 1
        except UnicodeDecodeError:
            # 既不是 GBK 也不是 ASCII，可能是数据损坏，用十六进制表示
            custom_data_decoded_parts.append(f"<{remaining_bytes[i : i + 1].hex()}>")
            i += 1

    custom_data_str = ''.join(custom_data_decoded_parts)
    
    # --- 提取浮标标识名字 (旧协议特定) ---
    buoy_name = None
    buoy_name_match = re.search(r'@@(.{1,6})@@$', custom_data_str)
    if buoy_name_match:
        buoy_name = buoy_name_match.group(1)
        custom_data_str = re.sub(r'@@(.{1,6})@@$', '', custom_data_str)
        
    parsed_data['自定义数据'] = custom_data_str # 移除标识后的自定义数据
    parsed_data['浮标标识名字'] = buoy_name # 保存提取到的浮标名字

    # 最终确定解析状态
    if 'parse_error_detail' in parsed_data:
        parsed_data['parse_status_text'] = parsed_data.get('parse_status_text', '解析错误')
        parsed_data['parse_status_class'] = "error-text"
    elif 'parse_warning_detail' in parsed_data:
        parsed_data['parse_status_text'] = f"解析警告: {parsed_data['parse_warning_detail'].strip()}"
        parsed_data['parse_status_class'] = "error-text"
    else:
        parsed_data['parse_status_text'] = "解析成功"
        parsed_data['parse_status_class'] = "success-text"

    return parsed_data

def _parse_new_protocol(ascii_data_str, hex_str):
    """
    解析新的协议电文内容（0x48开头，ASCII格式，@分隔符）。
    格式: 浮标标识名字@状态码@定位日期DDMMYY@定位时间HHMMSS.sss@纬度@纬度方向@经度@经度方向@高程@地速@航向
    """
    parsed_data = {"raw_hex_content": hex_str, "protocol_type": "新协议 (0x48)"}
    parts = ascii_data_str.split('@')

    # 预设所有字段为N/A或None，以防解析失败，并确保所有协议都有这些字段
    parsed_data['数据标识'] = "0x48 (新协议)" 
    parsed_data['定位时间'] = 'N/A'
    parsed_data['纬度半球'] = 'N/A'
    parsed_data['原始纬度值'] = 'N/A'
    parsed_data['经度半球'] = 'N/A'
    parsed_data['原始经度值'] = 'N/A'
    parsed_data['高程'] = 'N/A'
    parsed_data['隔离符'] = 'N/A' # 新协议无此概念
    parsed_data['自定义数据'] = 'N/A'
    parsed_data['浮标标识名字'] = None # 默认无浮标名字

    # 至少需要11个字段才能完整解析
    if len(parts) < 11: 
        parsed_data['parse_status_text'] = "新协议解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = f"新协议字段数量不足。期望至少11个，实际{len(parts)}个。"
        # 尝试解析可用的部分以提供部分信息
        if len(parts) > 0:
            parsed_data['浮标标识名字'] = parts[0]
        if len(parts) > 3:
            parsed_data['定位时间'] = parts[3]
        if len(parts) > 9: # 至少有高程，则尝试把高程及以后都放进自定义数据
            parsed_data['高程'] = parts[9]
            parsed_data['自定义数据'] = '@'.join(parts[10:]) if len(parts) > 10 else ''
        elif len(parts) > 0: # 如果连高程都没，那把剩余的都放自定义数据
             parsed_data['自定义数据'] = '@'.join(parts[1:])
        return parsed_data

    try:
        parsed_data['浮标标识名字'] = parts[0]
        # parts[1] (状态码) 和 parts[2] (定位日期) 不解析不显示
        parsed_data['定位时间'] = parts[3] # 定位时间HHMMSS.sss
        # parts[4] (定位状态) 不解析不显示
        parsed_data['原始纬度值'] = parts[5] # 纬度
        parsed_data['纬度半球'] = parts[6] # 纬度方向
        parsed_data['原始经度值'] = parts[7] # 经度
        parsed_data['经度半球'] = parts[8] # 经度方向
        parsed_data['高程'] = parts[9] # 高程
        # 自定义数据为剩余部分，即 parts[10] 及以后 (地速@航向)
        parsed_data['自定义数据'] = '@'.join(parts[10:])

        parsed_data['parse_status_text'] = "解析成功"
        parsed_data['parse_status_class'] = "success-text"

    except IndexError as e:
        parsed_data['parse_status_text'] = "新协议解析错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = f"新协议字段索引错误: {e}。原始数据片段: {parts}"
    except Exception as e:
        parsed_data['parse_status_text'] = "新协议解析未知错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = f"解析过程中发生意外错误: {e}。原始数据片段: {parts}"

    return parsed_data

def parse_hex_content(hex_str):
    """
    根据协议类型调度解析函数。
    """
    parsed_data = {"raw_hex_content": hex_str}

    if not isinstance(hex_str, str) or not re.fullmatch(r'^[0-9a-fA-F]*$', hex_str):
        parsed_data['parse_status_text'] = "十六进制字符串格式错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "输入不是有效的十六进制字符串。"
        return parsed_data
    
    # 空字符串处理
    if not hex_str:
        parsed_data['parse_status_text'] = "内容为空"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "接收到的 Content 字段为空。"
        return parsed_data

    try:
        byte_data = binascii.unhexlify(hex_str)
    except binascii.Error as e:
        parsed_data['parse_status_text'] = f"十六进制解码错误"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = f"十六进制字符串解码失败: {e}"
        return parsed_data

    if not byte_data: # 解码后可能为空
        parsed_data['parse_status_text'] = "内容为空"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "解码后的字节数据为空。"
        return parsed_data

    # 检查解码后的第一个字节
    if byte_data[0] == 0xA4:
        return _parse_old_protocol(byte_data, hex_str)
    elif byte_data[0] == 0x48: # 对应新协议，Content字段第一个字节是48
        try:
            # 对于0x48开头的协议，后续内容是ASCII字符串
            # 整个byte_data解码为ASCII，第一个字节0x48对应的ASCII是'H'
            ascii_data_str = byte_data.decode('ascii')
            return _parse_new_protocol(ascii_data_str, hex_str)
        except UnicodeDecodeError:
            parsed_data['parse_status_text'] = "解析失败"
            parsed_data['parse_status_class'] = "error-text"
            parsed_data['parse_error_detail'] = "新协议(0x48开头)后续内容无法解码为ASCII。"
            # 尝试为未知协议填充一些默认值，避免后续流程崩溃
            parsed_data['数据标识'] = f"0x{byte_data[0]:02X} (新协议但ASCII解码失败)"
            parsed_data['定位时间'] = 'N/A'
            parsed_data['纬度半球'] = 'N/A'
            parsed_data['原始纬度值'] = 'N/A'
            parsed_data['经度半球'] = 'N/A'
            parsed_data['原始经度值'] = 'N/A'
            parsed_data['高程'] = 'N/A'
            parsed_data['隔离符'] = 'N/A'
            try: # 尝试将剩余字节作为自定义数据处理
                parsed_data['自定义数据'] = byte_data[1:].decode('gbk', errors='replace')
            except:
                parsed_data['自定义数据'] = f"<{binascii.hexlify(byte_data[1:]).decode()}> (未知编码)"
            parsed_data['浮标标识名字'] = None
            return parsed_data
        except Exception as e:
            parsed_data['parse_status_text'] = "新协议(0x48开头)解析未知错误"
            parsed_data['parse_status_class'] = "error-text"
            parsed_data['parse_error_detail'] = f"新协议解析过程中发生意外错误: {e}"
            return parsed_data
    else:
        parsed_data['parse_status_text'] = "解析失败"
        parsed_data['parse_status_class'] = "error-text"
        parsed_data['parse_error_detail'] = "未知协议类型，既非0xA4开头，也非0x48开头。"
        # 尝试为未知协议填充一些默认值，避免后续流程崩溃
        parsed_data['数据标识'] = f"0x{byte_data[0]:02X} (未知)"
        parsed_data['定位时间'] = 'N/A'
        parsed_data['纬度半球'] = 'N/A'
        parsed_data['原始纬度值'] = 'N/A'
        parsed_data['经度半球'] = 'N/A'
        parsed_data['原始经度值'] = 'N/A'
        parsed_data['高程'] = 'N/A'
        parsed_data['隔离符'] = 'N/A'
        try: # 尝试将剩余字节作为自定义数据处理
            parsed_data['自定义数据'] = byte_data[1:].decode('gbk', errors='replace')
        except:
            parsed_data['自定义数据'] = f"<{binascii.hexlify(byte_data[1:]).decode()}> (未知编码)"
        parsed_data['浮标标识名字'] = None
        return parsed_data

def convert_dmm_to_decimal(dmm_str, hemisphere):
    """
    将 ddmm.mmmmm 或 dddmm.mmmmm 格式转换为十进制。
    """
    if not isinstance(dmm_str, str) or not re.match(r'^\d+\.\d+$', dmm_str):
        return None
    try:
        parts = dmm_str.split('.')
        
        # 根据字符串长度判断是 ddmm 还是 dddmm
        if len(parts[0]) == 4: # ddmm.mmmmm (例如 N4005.76783)
            degrees = int(parts[0][:2])
            minutes = float(parts[0][2:] + '.' + parts[1])
        elif len(parts[0]) == 5: # dddmm.mmmmm (例如 E11621.57798)
            degrees = int(parts[0][:3])
            minutes = float(parts[0][3:] + '.' + parts[1])
        else:
            return None # 格式不匹配
        
        decimal_deg = degrees + minutes / 60
        
        if hemisphere in ['S', 'W']:
            decimal_deg = -decimal_deg
        return round(decimal_deg, 6) # 保留6位小数
    except Exception:
        return None

def format_coords(hemisphere, value_str):
    """
    格式化经纬度，并处理无效值。
    """
    if not isinstance(hemisphere, str) or not hemisphere.strip():
        hemisphere = ''
    if not isinstance(value_str, str) or not value_str.strip():
        value_str = ''

    # 检查是否为纯数字或带小数点，兼容新旧协议
    # 新协议的纬度例如 "3411.8519"，经度 "10851.2901"
    # 旧协议的纬度例如 "4005.76783"，经度 "11621.57798"
    if not re.match(r'^\d+\.\d+$', value_str):
        return f"{hemisphere}{value_str} (格式错误或缺失)"

    try:
        # 尝试解析为度分格式，兼容两种长度的度
        match_ddmm = re.match(r'^(\d{2})(\d{2}\.\d+)$', value_str) # 纬度 ddmm.mmmmm
        match_dddmm = re.match(r'^(\d{3})(\d{2}\.\d+)$', value_str) # 经度 dddmm.mmmmm

        degree_part = ''
        minute_part = ''
        
        if match_ddmm:
            degree_part = match_ddmm.group(1)
            minute_part = match_ddmm.group(2)
        elif match_dddmm:
            degree_part = match_dddmm.group(1)
            minute_part = match_dddmm.group(2)
        else:
            # 如果不匹配标准格式，直接显示原始值，避免不必要的报错
            return f"{hemisphere}{value_str} (度分格式不符)"

        hemi_map = {
            'N': '北纬', 'S': '南纬',
            'E': '东经', 'W': '西经'
        }
        hemi_full = hemi_map.get(hemisphere.upper(), hemisphere) # 默认使用原始半球标识

        # 确保分的小数部分保留5位或更多，这里统一使用原始的minute_part
        return f"{hemi_full}{degree_part}°{minute_part}'"
    except Exception as e:
        return f"{hemisphere}{value_str} (解析失败: {e})"

def format_altitude(alt_str):
    """
    格式化高程，并处理无效值。
    兼容旧协议的 ±xxxxx.x 和新协议的 xxx.xxxx
    """
    if not isinstance(alt_str, str) or not alt_str.strip():
        return "N/A" 

    # 尝试解析为浮点数
    try:
        value = float(alt_str)
        # 统一格式化为带符号的，保留一位小数
        formatted_value = f"{value:+.1f}" 
        return f"{formatted_value}米"
    except ValueError:
        # 如果不能直接转为浮点数，可能是格式不规范或包含非数字字符
        return f"{alt_str} (格式错误或缺失)"
    except Exception as e:
        return f"{alt_str} (解析失败: {e})"


def format_parsed_data_for_display(parsed_data, raw_post_data, receive_time):
    """
    将解析后的数据格式化为更友好的显示格式。
    此函数现在直接返回一个扁平化的字典，包含所有用于显示和搜索的字段。
    同时增加十进制经纬度字段，方便地图使用。
    """
    formatted = {}

    original_id_number = raw_post_data.get('IdNumber', 'N/A')
    buoy_name = parsed_data.get('浮标标识名字')

    # --- 生成 display_id_name ---
    if buoy_name:
        formatted['display_id_name'] = f"{buoy_name}（{original_id_number}）"
    else:
        formatted['display_id_name'] = f"未定义名称（{original_id_number}）"
    # --- 结束新增需求 ---

    formatted['IdNumber'] = original_id_number # 原始ID仍然保留，用于内部查找和历史页面链接
    formatted['MessageId'] = raw_post_data.get('MessageId', 'N/A')
    formatted['DeliveryCount'] = raw_post_data.get('DeliveryCount', 'N/A')
    formatted['NetworkMode'] = raw_post_data.get('NetworkMode', 'N/A')
    formatted['接收时间'] = receive_time if receive_time else 'N/A'
    
    formatted['解析状态'] = {
        'text': parsed_data.get('parse_status_text', '未知状态'),
        'class': parsed_data.get('parse_status_class', '')
    }

    # 总是包含这些字段，用于展示原始信息，即使解析失败也应有回退值
    formatted['数据标识'] = parsed_data.get('数据标识', 'N/A')
    formatted['定位时间'] = parsed_data.get('定位时间', 'N/A') # 原始格式时间
    
    # 原始经纬高程值
    raw_lat_val = parsed_data.get('原始纬度值', 'N/A')
    raw_lon_val = parsed_data.get('原始经度值', 'N/A')
    raw_alt_val = parsed_data.get('高程', 'N/A')

    # 进行详细的经纬度高程解析和格式化
    lat_hemi = parsed_data.get('纬度半球')
    formatted['纬度'] = format_coords(lat_hemi, raw_lat_val) # 格式化后的纬度字符串
    formatted['decimal_latitude'] = convert_dmm_to_decimal(raw_lat_val, lat_hemi)


    lon_hemi = parsed_data.get('经度半球')
    formatted['经度'] = format_coords(lon_hemi, raw_lon_val) # 格式化后的经度字符串
    formatted['decimal_longitude'] = convert_dmm_to_decimal(raw_lon_val, lon_hemi)

    formatted['高程'] = format_altitude(raw_alt_val) # 格式化后的高程

    formatted['自定义数据'] = parsed_data.get('自定义数据', 'N/A') # 移除浮标标识后的自定义数据
    formatted['浮标标识名字'] = buoy_name if buoy_name else "N/A" # 浮标标识名字

    # 添加原始POST数据，方便前端搜索和调试
    formatted['raw_post_data_json'] = json.dumps(raw_post_data, indent=2, ensure_ascii=False)

    return formatted

# --- API 路由 ---
@app.route('/api/receive', methods=['POST'])
def receive_post_data():
    req_id = request.headers.get('RequestId', str(uuid.uuid4()))
    response_payload = {"RequestId": req_id}

    if not request.is_json:
        response_payload["Code"] = "error: Content-Type must be application/json"
        print(f"[{datetime.datetime.now()}] [ERROR] Content-Type 不是 application/json。")
        return jsonify(response_payload), 400

    data = request.get_json()
    if not data:
        response_payload["Code"] = "error: Invalid JSON payload"
        print(f"[{datetime.datetime.now()}] [ERROR] 无效的 JSON payload。")
        return jsonify(response_payload), 400

    required_fields = ["IdNumber", "Content", "Time", "MessageId", "DeliveryCount", "NetworkMode"]
    for field in required_fields:
        if field not in data:
            response_payload["Code"] = f"error: Missing required field '{field}'"
            print(f"[{datetime.datetime.now()}] [ERROR] 缺少必填字段 '{field}'。Payload: {data}")
            return jsonify(response_payload), 400
        if not isinstance(data[field], str):
             response_payload["Code"] = f"error: Field '{field}' must be a string"
             print(f"[{datetime.datetime.now()}] [ERROR] 字段 '{field}' 必须是字符串。Payload: {data}")
             return jsonify(response_payload), 400

    id_number = data['IdNumber']
    content_hex = data['Content']
    receive_time = datetime.datetime.now().isoformat(timespec='seconds') # 精确到秒

    print(f"[{datetime.datetime.now()}] [INFO] API收到请求 - IdNumber: {id_number}, MessageId: {data['MessageId']}")

    parsed_content = parse_hex_content(content_hex)
    print(f"[{datetime.datetime.now()}] [INFO] 解析结果 (Id:{id_number}, MsgId:{data['MessageId']}): {parsed_content.get('parse_status_text', '未知状态')}")
    
    message_entry = {
        "raw_post_data": data,
        "parsed_content": parsed_content,
        "receive_time": receive_time
    }

    if id_number not in DATA_STORE:
        DATA_STORE[id_number] = []
    
    # 始终添加到列表开头，保持最新消息在最前面
    DATA_STORE[id_number].insert(0, message_entry)
    
    save_data()
    print(f"[{datetime.datetime.now()}] [INFO] 数据已为 IdNumber {id_number} 保存并持久化。")

    response_payload["Code"] = "ok"
    return jsonify(response_payload), 200

# 修正后的 API 接口：获取所有 ID 的最新有效位置数据
@app.route('/api/latest_locations', methods=['GET'])
def api_latest_locations():
    # 接收前端可能传递的原始ID字符串，用于筛选
    selected_ids_str = request.args.get('id_numbers') 
    if selected_ids_str:
        selected_ids = [s.strip() for s in selected_ids_str.split(',') if s.strip()]
    else:
        # 如果没有指定ID，则返回 DATA_STORE 中所有ID的最新数据
        selected_ids = list(DATA_STORE.keys()) 

    latest_data_for_response = []

    for id_num in selected_ids: # 遍历所有**需要查询**的原始ID
        messages_for_id = DATA_STORE.get(id_num, [])
        
        latest_valid_message_entry = None
        # DATA_STORE中每个ID的消息列表已按接收时间倒序排列，可以直接遍历
        for msg_entry in messages_for_id:
            # 格式化消息以检查经纬度有效性，并获取display_id_name等
            formatted_msg_temp = format_parsed_data_for_display(
                msg_entry.get('parsed_content', {}),
                msg_entry.get('raw_post_data', {}),
                msg_entry.get('receive_time', None)
            )
            
            # 检查 decimal_latitude 和 decimal_longitude 是否有效
            if (formatted_msg_temp['decimal_latitude'] is not None and 
                formatted_msg_temp['decimal_longitude'] is not None):
                latest_valid_message_entry = formatted_msg_temp # 直接使用格式化后的数据
                break # 找到第一个有效消息，停止查找
        
        if latest_valid_message_entry:
            latest_data_for_response.append({
                'IdNumber': latest_valid_message_entry['IdNumber'],
                'display_id_name': latest_valid_message_entry['display_id_name'], # 新增
                'MessageId': latest_valid_message_entry['MessageId'],
                '接收时间': latest_valid_message_entry['接收时间'],
                '定位时间': latest_valid_message_entry['定位时间'],
                '纬度': latest_valid_message_entry['纬度'], # 格式化后的原始纬度
                '经度': latest_valid_message_entry['经度'], # 格式化后的原始经度
                '高程': latest_valid_message_entry['高程'],
                'decimal_latitude': latest_valid_message_entry['decimal_latitude'], # 十进制纬度
                'decimal_longitude': latest_valid_message_entry['decimal_longitude'], # 十进制经度
                '自定义数据': latest_valid_message_entry['自定义数据'],
                '浮标标识名字': latest_valid_message_entry['浮标标识名字'], # 新增
            })
    
    print(f"[{datetime.datetime.now()}] [INFO] 准备返回 {len(latest_data_for_response)} 条最新有效位置数据 (过滤ID: {', '.join(selected_ids) if selected_ids else '所有ID'})。")
    return jsonify(latest_data_for_response)


# --- Web 路由 ---
@app.route('/')
def index():
    print(f"[{datetime.datetime.now()}] [INFO] 访问主页 '/'。")
    
    # 准备所有 ID 的所有消息，并进行格式化
    all_messages_for_frontend = {} # 格式: { "原始ID": [formatted_msg1, formatted_msg2, ...], ... }
    
    # 存储原始ID到其最新display_id_name的映射
    id_to_display_name_map = {} 

    # 遍历DATA_STORE，确保所有消息都经过format_parsed_data_for_display处理
    # 并且构建id_to_display_name_map和all_messages_for_frontend
    for id_num in sorted(DATA_STORE.keys()): # 按原始ID排序
        messages_for_id = []
        if id_num in DATA_STORE:
            # 消息已按接收时间倒序排列，第一个就是最新的
            for i, msg_entry in enumerate(DATA_STORE[id_num]):
                formatted_msg = format_parsed_data_for_display(
                    msg_entry.get('parsed_content', {}),
                    msg_entry.get('raw_post_data', {}),
                    msg_entry.get('receive_time', None)
                )
                messages_for_id.append(formatted_msg)
                
                # 记录原始ID和其对应的最新显示名称 (来自第一条消息)
                if i == 0:
                    id_to_display_name_map[id_num] = formatted_msg['display_id_name']
                
            if messages_for_id: # 只添加有消息的ID
                all_messages_for_frontend[id_num] = messages_for_id

    # 为前端生成一个包含 display_id_name 和原始 IdNumber 的列表，用于下拉选择框
    display_id_options = []
    # 遍历按原始ID排序的键，确保选项的顺序一致
    for id_num in sorted(id_to_display_name_map.keys()):
        display_id_options.append({
            'original_id': id_num,
            'display_name': id_to_display_name_map[id_num]
        })

    unique_display_names_count = len(set(id_to_display_name_map.values())) # 统计不重复的显示名称数量
    total_messages_count = sum(len(v) for v in all_messages_for_frontend.values())

    print(f"[{datetime.datetime.now()}] [INFO] 主页准备向前端发送所有 {unique_display_names_count} 个显示ID ({len(all_messages_for_frontend)} 个原始ID) 的 {total_messages_count} 条消息。")
    return render_template(
        'index.html',
        all_messages_grouped_by_id=all_messages_for_frontend, 
        display_id_options=display_id_options, # 传递包含显示名称和原始ID的列表
        unique_id_count_total=unique_display_names_count, # 统计显示名称的数量
        total_messages_count_total=total_messages_count
    )

@app.route('/history/<string:id_number_param>')
def history(id_number_param):
    print(f"[{datetime.datetime.now()}] [INFO] 访问历史页面 '/history/{id_number_param}'。")
    original_id_number = id_number_param # 历史页面仍然以原始 ID 为路由参数

    if original_id_number not in DATA_STORE or not DATA_STORE[original_id_number]:
        print(f"[{datetime.datetime.now()}] [WARN] 未找到 ID '{original_id_number}' 的历史数据。")
        return render_template('not_found.html', id_number=original_id_number), 404

    historical_messages_raw = DATA_STORE[original_id_number]
    
    historical_messages_formatted = []
    current_display_id_name = ""
    for msg_entry in historical_messages_raw:
        formatted_msg = format_parsed_data_for_display(
            msg_entry.get('parsed_content', {}),
            msg_entry.get('raw_post_data', {}),
            msg_entry.get('receive_time', None)
        )
        historical_messages_formatted.append(formatted_msg)
        # 提取最新消息的显示名称作为页面标题（消息已按时间倒序）
        if not current_display_id_name: 
            current_display_id_name = formatted_msg['display_id_name']

    query = request.args.get('query', '') 

    print(f"[{datetime.datetime.now()}] [INFO] ID '{original_id_number}' 历史页面已加载，包含 {len(historical_messages_formatted)} 条消息。")
    return render_template(
        'history.html',
        id_number=original_id_number,
        display_id_name=current_display_id_name, # 传递显示名称
        historical_messages=historical_messages_formatted, 
        initial_query=query
    )

@app.route('/map')
def map_page():
    print(f"[{datetime.datetime.now()}] [INFO] 访问地图页面 '/map'。")
    
    all_messages_for_frontend = {} # 格式: { "原始ID": [formatted_msg1, formatted_msg2, ...], ... }
    id_to_display_name_map = {}

    for id_num in sorted(DATA_STORE.keys()):
        messages_for_id = []
        if id_num in DATA_STORE:
            for i, msg_entry in enumerate(DATA_STORE[id_num]):
                formatted_msg = format_parsed_data_for_display(
                    msg_entry.get('parsed_content', {}),
                    msg_entry.get('raw_post_data', {}),
                    msg_entry.get('receive_time', None)
                )
                messages_for_id.append(formatted_msg)
                
                if i == 0:
                    id_to_display_name_map[id_num] = formatted_msg['display_id_name']
                
            if messages_for_id:
                all_messages_for_frontend[id_num] = messages_for_id

    display_id_options = []
    for id_num in sorted(id_to_display_name_map.keys()):
        display_id_options.append({
            'original_id': id_num,
            'display_name': id_to_display_name_map[id_num]
        })

    return render_template(
        'map.html',
        amap_jsapi_key=AMAP_JSAPI_KEY,
        all_messages_grouped_by_id=all_messages_for_frontend,
        display_id_options=display_id_options # 传递包含显示名称和原始ID的列表
    )


@app.errorhandler(404)
def page_not_found(e):
    print(f"[{datetime.datetime.now()}] [WARN] 发生 404 错误: {request.path}")
    return render_template('not_found.html'), 404

# --- 应用启动 ---
if __name__ == '__main__':
    load_data()
    print(f"[{datetime.datetime.now()}] [INFO] Flask 应用启动中...")
    # debug=True 会在代码更改时自动重新加载，但在生产环境应设置为 False
    app.run(host='0.0.0.0', port=5000, debug=True)
